/**
 * Created by Richard Radlherr.
 * Date: 04.06.2006 20:58
 */

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using TagTool.Core;
using System.Reflection;
using System.Collections.Generic;

namespace TagTool.Components
{
	/**
	 * The Nodepanel represents an arbitrary Node derived from BaseNode
	 */
	public partial class NodePanel
	{
		private List<InputSlotPanel> inputs = new List<InputSlotPanel>();
		private List<OutputSlotPanel> outputs = new List<OutputSlotPanel>();

		private BaseNode node;

		private bool move = false;
		private int ox;
		private int oy;
        bool collapsed = false;

		public NodePanel()
		{
			InitializeComponent();
		}
		
		public BaseNode Node
		{
			get { return node; }
			set 
			{
				node = value;
				Left = node.LocX;
				Top = node.LocY;
				Initialize();
			}
		}

		public Component this[String index]
		{
			get 
			{
				foreach(Control c in Controls)
				{
					if ((c is InputSlotPanel || c is OutputSlotPanel) && ((Slot)c.Tag).Name == index)
					{
						return (Component)c;
					}
				}
				return null;
			}
		}
		
		private void AddMenuItem(Control tag, String name, CheckState checkState)
		{
        	ToolStripMenuItem item = new ToolStripMenuItem();
        	item.Checked = true;
        	item.CheckState = checkState;
        	item.CheckOnClick = true;
        	item.Text = name;
        	item.CheckedChanged += new EventHandler(OnShowSlotClick);
        	menuItemShowSlot.DropDownItems.Add(item);
        	item.Tag = tag;
		}
		
		/**
		 * Iterate through the Attributes of the attachet BaseNode- type
		 * an se a SlotPanel for ech foun Slot attribute
		 * Select the propper SlotPanelType according to the given SlotType
		 */
		private void Initialize()
		{
			this.Cursor = Cursors.Arrow;
			if (node != null)
			{
				this.nodeTypeName.Text = node.Name;
				Height = nodeTypeName.Height;
				
				PropertyInfo[] props = node.GetType().GetProperties();
				int h = nodeTypeName.Height - 1;
				
				foreach(PropertyInfo prop in props)
				{
			        object[] atts;
			        atts = prop.GetCustomAttributes(typeof(NodeAttribute), true);
			        if (atts.GetLength(0) != 0)
			        {
			            NodeAttribute    att = (NodeAttribute) atts[0];
						Control panel;
						if (att.SlotType == SlotType.Input)
						{
							InputSlot inputSlot = (InputSlot)prop.GetValue(node, null);
							if (att.ValueTypeName != null)
			            	{
			            		inputSlot.ValueTypeName = att.ValueTypeName;
			            	}
			            	panel = new InputSlotPanel(inputSlot);
        					inputs.Add((InputSlotPanel)panel);
        					AddMenuItem(panel, inputSlot.Name, CheckState.Checked);
						}
			            else
			            {
			            	OutputSlot outputSlot = (OutputSlot)prop.GetValue(node, null);
			            	if (att.ValueTypeName != null)
			            	{
			            		outputSlot.ValueTypeName = att.ValueTypeName;
			            	}			            	
			            	panel = new OutputSlotPanel(outputSlot);
			            	outputs.Add((OutputSlotPanel)panel);
			            	AddMenuItem(panel, outputSlot.Name, CheckState.Checked);
			            }
			            
						panel.Width = Width;
						panel.Location = new Point(0, h);
						h += panel.Height - 1;
						
						panel.Cursor = Cursors.Arrow;
						this.Controls.Add(panel);
			        }
				}
				
				Height = h + 2;
			}
		}
		
		public void Attach()
		{
			foreach (InputSlotPanel p in inputs)
			{
				p.Attach();
			}
			foreach (OutputSlotPanel p in outputs)
			{
				p.Attach();
			}
		}
		
		public void Detach()
		{
			foreach (InputSlotPanel p in inputs)
			{
				p.Detach();
			}
			foreach (OutputSlotPanel p in outputs)
			{
				p.Detach();
			}
		}

		private void OnShowSlotClick(Object sender, EventArgs e)
		{
			ToolStripMenuItem item = (ToolStripMenuItem)sender;
			if (item.Checked)
			{
				((Control)item.Tag).Show();
			}
			else
			{
				((Control)item.Tag).Hide();
			}
			Reorganize();
		}
		
        public void Collapse()
        {
            Height = nodeTypeName.Height;
            bool first = true;
            foreach (Control c in Controls)
            {
                if (!first)
                {
                    c.Top = 0;
                }
                first = false;
            }
            collapsed = true;
            Parent.Invalidate();
        }
        
        private void SetMenuItemCheck(String name, bool check)
        {
        	foreach(ToolStripMenuItem s in this.menuItemShowSlot.DropDownItems)
        	{
        		if (s.Text.Equals(name))
        		{
        			s.Checked = check;
        		}
        	}
        }

        public void Expand()
        {
            bool first = true;
            int h = nodeTypeName.Height - 1;

            foreach (Control c in Controls)
            {
                if (!first)
                {
                	if (c.Visible)
                	{
                    	c.Top = h;
                    	h += c.Height - 1;
                	}
                	else 
                	{
                		c.Top = 0;
                	}
                	SetMenuItemCheck(c.Name, c.Visible);
                }
                first = false;
            }
            Height = h + 2;
            collapsed = false;
            Parent.Invalidate();
        }
        
        public void Reorganize()
        {
        	if (!collapsed)
        	{
        		Expand();
        	}
        }

		private void NodeTypeNameMouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Left)
			{
				this.Select();
				ox = e.X;
				oy = e.Y;
				move = true;
			}
			else if (e.Button == MouseButtons.Right)
			{
				contextMenuStrip.Show(nodeTypeName.PointToScreen(e.Location));
			}
		}

		private void NodeTypeNameMouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			if (move)
			{
				if (e.X != ox || e.Y != oy)
				{	
					this.Left += e.X - ox;
					this.Top += e.Y - oy;
				}
			}
		}
		
		private void NodeTypeNameMouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Left)
			{
				move = false;
			}
		}
		

		private void NodePanelEnter(object sender, System.EventArgs e)
		{
			this.nodeTypeName.BackColor = Color.BurlyWood;
		}

		private void NodePanelLeave(object sender, System.EventArgs e)
		{
			this.nodeTypeName.BackColor = Color.AntiqueWhite;
		}
	
		public void PaintConnections(Graphics g)
		{
			foreach(Control c in Controls)
			{
				if (c is InputSlotPanel)
				{
					((InputSlotPanel)c).PaintConnection(g);
				}
			}
		}
		
		public InputSlotPanel Find(InputSlot slot)
		{
			foreach(Control c in Controls)
			{
				if (c is InputSlotPanel)
				{
					if (((InputSlotPanel)c).Slot == slot)
					{
						return (InputSlotPanel)c;
					}
				}
			}
			return null;
		}
		
		public OutputSlotPanel Find(OutputSlot slot)
		{
			foreach(Control c in Controls)
			{
				if (c is OutputSlotPanel)
				{
					if (((OutputSlotPanel)c).Slot == slot)
					{
						return (OutputSlotPanel)c;
					}
				}
			}
			return null;
		}
		
		private void NodePanelMove(object sender, System.EventArgs e)
		{
			if (Parent != null)
			{
				node.LocX = Left;
				node.LocY = Top;
				Parent.Invalidate();
			}
		}

        private void nodeTypeName_DoubleClick(object sender, EventArgs e)
        {
            if (collapsed)
            {
                Expand();
            }
            else
            {
                Collapse();
            }
        }
		
		
		void MenuItemCollapseClick(object sender, System.EventArgs e)
		{
			if (collapsed)
			{
				Expand();
			}
			else
			{
				Collapse();
			}
		}
		
		void MenuItemDeleteClick(object sender, System.EventArgs e)
		{
			Control c = Parent;
			this.Dispose();
			c.Invalidate();
		}
	}
}
